﻿from datetime import datetime, timezone

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import or_, select
from sqlalchemy.ext.asyncio import AsyncSession

from app.api.deps import get_current_user, get_db
from app.models.anniversary import Anniversary
from app.models.user import User
from app.schemas import anniversary as anniversary_schema
from app.api.response import success_response
from app.services.notification_manager import notification_manager
from app.services.relationship_utils import get_partner_email
from app.services.lunar_utils import parse_lunar_str, next_solar_from_lunar

router = APIRouter(redirect_slashes=False)


def _is_accessible(record: Anniversary | None, user: User) -> bool:
  if not record:
    return False
  if record.user_id == user.id:
    return True
  if user.active_relationship_id and record.relationship_id == user.active_relationship_id:
    return True
  return False


@router.get('')
async def list_anniversaries(
  limit: int = 50,
  offset: int = 0,
  current_user: User = Depends(get_current_user),
  session: AsyncSession = Depends(get_db),
) -> dict:
  filters = []
  if current_user.active_relationship_id:
    filters.append(
      or_(
        Anniversary.user_id == current_user.id,
        Anniversary.relationship_id == current_user.active_relationship_id,
      )
    )
  else:
    filters.append(Anniversary.user_id == current_user.id)

  safe_limit = max(1, min(limit, 100))
  safe_offset = max(0, offset)

  result = await session.scalars(
    select(Anniversary)
    .where(*filters)
    .order_by(Anniversary.date.asc())
    .offset(safe_offset)
    .limit(safe_limit)
  )
  items = result.all()
  payload = []
  today = datetime.now(timezone.utc).date()
  for item in items:
    data = anniversary_schema.AnniversaryResponse.model_validate(item, from_attributes=True).model_dump(mode='json')
    # 计算下一次发生日期（支持农历）
    next_date = None
    if data.get('is_lunar') and data.get('lunar_date_str'):
      patt = parse_lunar_str(str(data['lunar_date_str']))
      if patt:
        nd = next_solar_from_lunar(patt, today)
        if nd:
          next_date = nd.isoformat()
    # 默认使用公历基准的下一次（与 scheduler 保持一致）
    if not next_date:
      base = data.get('date')
      if isinstance(base, str):
        from datetime import date as _date
        try:
          base_d = _date.fromisoformat(base)
          # yearly-like 默认逻辑：如果已过去，则顺延一年
          if base_d < today:
            next_date = base_d.replace(year=today.year)
            if next_date < today:
              next_date = next_date.replace(year=today.year + 1)
            next_date = next_date.isoformat()
          else:
            next_date = base
        except Exception:
          next_date = base
    data['next_date'] = next_date or data.get('date')
    # 计算剩余天数
    try:
      if data['next_date']:
        from datetime import date as _date
        nd = _date.fromisoformat(str(data['next_date']))
        data['days_until'] = (nd - today).days
    except Exception:
      pass
    payload.append(data)
  return success_response({
    'items': payload,
    'next_offset': safe_offset + len(payload) if len(payload) == safe_limit else None,
  })


@router.post('', status_code=status.HTTP_201_CREATED)
async def create_anniversary(
  payload: anniversary_schema.AnniversaryCreate,
  current_user: User = Depends(get_current_user),
  session: AsyncSession = Depends(get_db),
) -> dict:
  # 若仅提供农历信息且未提供公历 date，则将“下一次公历发生日”作为基准存入
  from datetime import datetime as _dt, timezone as _tz
  today = _dt.now(_tz.utc).date()
  safe_date = payload.date
  if not safe_date and payload.is_lunar and payload.lunar_date_str:
    patt = parse_lunar_str(payload.lunar_date_str)
    if patt:
      nd = next_solar_from_lunar(patt, today)
      if nd:
        safe_date = nd
  if not safe_date:
    safe_date = today
  anniversary = Anniversary(
    user_id=current_user.id,
    relationship_id=current_user.active_relationship_id,
    name=payload.name,
    date=safe_date,
    recurrence=payload.recurrence,
    reminder_offset_days=payload.reminder_offset_days,
    is_lunar=payload.is_lunar,
    lunar_date_str=payload.lunar_date_str,
    countdown_mode=payload.countdown_mode,
  )
  session.add(anniversary)
  await session.commit()
  await session.refresh(anniversary)
  response = anniversary_schema.AnniversaryResponse.model_validate(anniversary, from_attributes=True)

  recipients = {current_user.email}
  partner_email = await get_partner_email(session, current_user)
  if partner_email:
    recipients.add(partner_email)
  await notification_manager.notify_anniversary_created(
    recipient_emails=recipients,
    creator_name=current_user.username,
    anniversary_name=anniversary.name,
    anniversary_date=str(anniversary.date),
  )
  return success_response(response.model_dump(mode='json'))


@router.put('/{anniversary_id}')
async def update_anniversary(
  anniversary_id: int,
  payload: anniversary_schema.AnniversaryUpdate,
  current_user: User = Depends(get_current_user),
  session: AsyncSession = Depends(get_db),
) -> dict:
  anniversary = await session.get(Anniversary, anniversary_id)
  if not _is_accessible(anniversary, current_user):
    raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail='Anniversary not found')

  data = payload.model_dump(exclude_unset=True)
  # 若切换为农历并提供 lunar_date_str，但未显式传入 date，则自动回填下一次公历发生日
  if data.get('is_lunar') and data.get('lunar_date_str') and 'date' not in data:
    from datetime import datetime as _dt, timezone as _tz
    today = _dt.now(_tz.utc).date()
    patt = parse_lunar_str(str(data['lunar_date_str']))
    if patt:
      nd = next_solar_from_lunar(patt, today)
      if nd:
        data['date'] = nd

  for field, value in data.items():
    setattr(anniversary, field, value)

  session.add(anniversary)
  await session.commit()
  await session.refresh(anniversary)
  response = anniversary_schema.AnniversaryResponse.model_validate(anniversary, from_attributes=True)
  return success_response(response.model_dump(mode='json'))


@router.delete('/{anniversary_id}')
async def delete_anniversary(
  anniversary_id: int,
  current_user: User = Depends(get_current_user),
  session: AsyncSession = Depends(get_db),
) -> dict:
  anniversary = await session.get(Anniversary, anniversary_id)
  if not _is_accessible(anniversary, current_user):
    raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail='Anniversary not found')

  anniversary.deleted_at = datetime.now(tz=timezone.utc)
  session.add(anniversary)
  await session.commit()
  return success_response()
